package top.frsf;

import javax.swing.*;
import java.awt.*;
import java.util.concurrent.Semaphore;

/**
 * @Author FRSF
 * @Date 2022/5/12 21:57
 * @Description
 **/
public class MainGUI extends JFrame {
    //  用户屏幕尺寸
    Integer widget;
    Integer height;
    String length;

    //  输入行文本框 * 3
    JTextField t_size, t_pro, t_cus = null;
    //  启动，停止按钮
    Button b_start, b_stop = null;
    //  多行文本显示框
    JTextArea output = null;
    JScrollPane scrollPane = null;
    //  演示界面
    JPanel show1 = null;
    JPanel show2 = null;
    JPanel show3 = null;

    //  数据
    //  已生产数目
    static Integer count = 0;
    //  已消耗产品
    static Integer used = 0;
    //创建三个信号量
    //这个是生产者许可，最多可以获取10个许可，也就是说最多生产10个苹果。
    Semaphore provider = null;
    //这个是消费者许可。一个空盘子。
    Semaphore consumer = new Semaphore(0);
    //体现互斥的地方：保证生产者和消费者之间的交替进行 所以再设置一个mutex信号量
    Semaphore mutex = new Semaphore(1);


    public MainGUI() {
        //  图形界面初始化
        setTitle("Semaphore    【信工20.1 2010530138】");
        setLayout(null);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //  获取用户显示器大小
        Toolkit tool = Toolkit.getDefaultToolkit();
        Dimension screenSize = tool.getScreenSize();
        this.widget = screenSize.width;
        this.height = screenSize.height;
        length = new String(" ").repeat(widget / 3);
        setSize(widget, height);

        //  输入面板
        JPanel input = new JPanel(new GridLayout(4, 2));
        input.setBorder(BorderFactory.createTitledBorder("用户控制"));
        input.setBounds(0, 0, widget / 2, height / 3);
        input.setBackground(Color.LIGHT_GRAY);
        add(input);

        JLabel l_size = new JLabel("公共缓冲池大小:");
        JLabel l_pro = new JLabel("生产者线程数:");
        JLabel l_cus = new JLabel("消费者线程数:");

        t_size = new JTextField("");
        t_pro = new JTextField("");
        t_cus = new JTextField("");

        b_start = new Button("Start");
        b_start.setBackground(Color.pink);
        b_stop = new Button("Stop");
        b_stop.setBackground(Color.pink);

        input.add(l_size);
        input.add(t_size);
        input.add(l_pro);
        input.add(t_pro);
        input.add(l_cus);
        input.add(t_cus);
        input.add(b_start);
        input.add(b_stop);

        //  文本显示模块
        output = new JTextArea();
        output.setEditable(false);
        output.setFont(new Font("monospaced", Font.PLAIN, 15));
        scrollPane = new JScrollPane(output);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setBounds(widget / 2 + 50, 0, widget / 2 - 60, height / 3);
        scrollPane.setBorder(BorderFactory.createTitledBorder("输出信息"));
        add(scrollPane);

        //  演示界面1
        show1 = new JPanel();
        show1.setBorder(BorderFactory.createTitledBorder("待生产信号量"));
        show1.setBounds(0, height / 3 + 20, widget / 3 - 50, height - height / 3 - 60);
        add(show1);

        //  演示界面2
        show2 = new JPanel();
        show2.setBorder(BorderFactory.createTitledBorder("当前产品数量"));
        show2.setBounds(widget / 3, height / 3 + 20, widget / 3 - 50, height - height / 3 - 60);
        add(show2);


        //  演示界面3
        show3 = new JPanel();
        show3.setBorder(BorderFactory.createTitledBorder("消费产品数量"));
        show3.setBounds(widget - widget / 3, height / 3 + 20, widget / 3 - 50, height - height / 3 - 60);
        add(show3);


        //  相关数据初始化
        Init();

    }


    private void Init() {
        eventInit();
    }

    private void eventInit() {
        //  开始按钮
        b_start.addActionListener(event -> {
            String t_sizeText = t_size.getText().trim();
            String t_proText = t_pro.getText().trim();
            String t_cusText = t_cus.getText().trim();

            //  判断是否纯数字
            if (t_sizeText.matches("[0-9]+") && t_proText.matches("[0-9]+")
                    && t_cusText.matches("[0-9]+")) {
                int t_size = Integer.parseInt(t_sizeText);
                int t_pro = Integer.parseInt(t_proText);
                int t_cus = Integer.parseInt(t_cusText);
                output.append("初始化参数：\n");
                output.append("【公共缓冲池大小】" + t_sizeText);
                output.append("\t【生产者线程数】" + t_proText);
                output.append("\t【消费者线程数】" + t_cusText);
                output.append("\n");
                output.setCaretPosition(output.getText().length());
                provider = new Semaphore(t_size);

                //  循环产生进程
                for (int i = 0; i < t_pro; i++)
                    new Thread(new Producer()).start();
                for (int i = 0; i < t_cus; i++)
                    new Thread(new Consumer()).start();

            } else {
                output.append("输入框输入非数字！\n");
            }
        });

    }

    class Producer implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    provider.acquire();//生产者先行，获得许可，因为final Semaphore provider = new Semaphore(10);
                    mutex.acquire();
                    count++;// 生产一个苹果
                    output.append(Thread.currentThread().getName() +
                            "生产者生产，目前总共有" + count);
                    output.append("\n");
                    output.setCaretPosition(output.getText().length());
                    ChangePic12();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    mutex.release();
                    // acquire与release之间的关系：
                    // 在实现中不包含真正的许可对象，并且Semaphore也不会将许可与线程关联起来，因此在一个线程中获得的许可可以在另一个线程中释放。也就是说acquire与release并没有强制的一对一关系
                    consumer.release();//生产完苹果，消费者获取到了许可。
                }
            }
        }
    }

    class Consumer implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                try {
                    consumer.acquire();
                    mutex.acquire();
                    count--;
                    used++;
                    output.append(Thread.currentThread().getName()
                            + "消费者消费，目前总共有" + count);
                    output.append("\n");
                    output.setCaretPosition(output.getText().length());
                    ChangePic12();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    mutex.release();
                    provider.release();
                }
            }
        }
    }

    private void ChangePic12() throws InterruptedException {
        show1.removeAll();
        for (int i = 0; i < provider.availablePermits(); i++) {
            show1.add(new MyLabel(Color.green, length));
        }


        show2.removeAll();
        for (int i = 0; i < count; i++) {
            show2.add(new MyLabel(Color.CYAN, length));
        }


        if (used <= 30) {
            show3.removeAll();
            for (int i = 0; i < used; i++)
                show3.add(new MyLabel(Color.LIGHT_GRAY, length));
        }

        show3.setBorder(BorderFactory.createTitledBorder("已消费产品数量" + used));

        show1.setVisible(false);
        show1.setVisible(true);
        show2.setVisible(false);
        show2.setVisible(true);
        show3.setVisible(false);
        show3.setVisible(true);

        Thread.sleep(1000);
    }


}
